package modelo.mapa;

// paquetes de proyecto
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Observable;

import modelo.enemigos.Enemigo;
import modelo.interfaces.Posicionable;
import modelo.juego.Configuracion;

public class Mapa extends Observable implements Serializable {
	
	static final long serialVersionUID = -2450666704235706310L;
	private Casillero Listado[][];
	private int tamanio;
	private Collection<Casillero> camino;

	private void agregarAlCamino(int X, int Y) {
		this.Listado[X][Y].setEsCamino(true);
		this.camino.add(Listado[X][Y]);
		
	}
	
	public void redibujarCamino() {
		Iterator<Casillero> iterador = camino.iterator();
		Casillero actual;
		while (iterador.hasNext()){
			actual = iterador.next();
			actual.RecrearVista();
		}
		
	}
	// Carga el Camino desde una posicion random
	public void setCamino() /*{
		int X = (((int) Math.random() * tamanio / 2) + 9);
		int corteY = tamanio / 2;

		this.camino = new ArrayList<Casillero>();
		for (int Y = 0; (Y < corteY); Y++) {
			agregarAlCamino(X, Y);
		}
		for (int z = X; (z == X - 4); z--) {
			agregarAlCamino(z, corteY);
		}
		for (int Y = corteY; (Y < tamanio); Y++) {
			agregarAlCamino(X, Y);
		}
	}*/
	{
		int X = 0;
		int Y = 3;
		this.camino = new ArrayList<Casillero>();
		while (X < 20){
			agregarAlCamino(X, Y);
			X++;
		}
		while (Y< 35){
			agregarAlCamino(X, Y);
			Y++;
		}
		while (X <= Configuracion.TAMANIO_MAPA -1){
			agregarAlCamino(X, Y);
			X++;
		}
		//}
	}

	// Genero la matriz de Casilleros
	// Cada Casillero posee su Posicion en la matriz
	public Mapa(int tamanio) {
		
		this.tamanio = tamanio;
		this.Listado = new Casillero[tamanio][tamanio];
		for (int largo = 0; largo < tamanio; largo++) {
			for (int ancho = 0; ancho < tamanio; ancho++) {
				this.Listado[largo][ancho] = new Casillero(largo, ancho);
			}
		}
	}

	// Devuelve el primer Casillero correspondiente al camino
	public Casillero primeraPosicion() {
		Iterator<Casillero> aPrimero = camino.iterator();
		return aPrimero.next();
	}

	// Devuelve el siguiente Casillero del camino respecto al pasado por
	// referencia
	// Falta tirar excepcion si se encuentra en el ultimo casillero
	public Casillero proximaPosicionDeCamino(Casillero actual) {
		Iterator<Casillero> BuscaSiguiente = camino.iterator();
		Casillero puntero = null;
		while ((actual != puntero) && (BuscaSiguiente.hasNext())) {
			puntero = BuscaSiguiente.next();
		}

		return BuscaSiguiente.next();
	}

	public boolean esUltimaPosicion(Casillero actual) {
		Iterator<Casillero> BuscaSiguiente = camino.iterator();
		Casillero puntero = null;

		while ((actual != puntero) && (BuscaSiguiente.hasNext())) {
			puntero = BuscaSiguiente.next();
		}

		return !BuscaSiguiente.hasNext();
	}

	public boolean esCamino(Casillero PuntoCentral, int rango) {
		return PuntoCentral.getEsCamino();
	}

	public Casillero GetCasilleroXY(int x, int y) {
		return this.Listado[x][y];
	}

	// Modifica tanto el Posicionable, Casillero viejo y Casillero nuevo
	// para dejar al Posicionable en el Nuevo casillero
	public void actulizarPosicion(Casillero nueva_pos, Posicionable tipo) {
		this.removerPosicionable(tipo);
		this.posicionarPosicionable(nueva_pos, tipo);
	}

	// Modifica tanto el Posicionable como al Casillero nuevo
	// para dejar al Posicionable en el Nuevo casillero
	public void posicionarPosicionable(Casillero nueva_pos, Posicionable tipo) {
		nueva_pos.agregarElemento(tipo);
		tipo.setCasillero(nueva_pos);
	}

	// Modifica tanto el Posicionable como al Casillero
	// para dejar al Posicionable sin Casillero alguno
	public void removerPosicionable(Posicionable tipo) {
		Casillero Ubicacion = tipo.getCasillero();
		Ubicacion.sacarElemento(tipo);
		tipo.setCasillero(null);
	}

	// Devuelve un listado de TODOS los Posicionables que se encuentran en el
	// rango
	public Collection<Posicionable> elementosEnRango(Casillero PuntoCentral,
			int rango) {
		Posicion lugar = PuntoCentral.getPosicion();
		int largo = lugar.getX();
		int ancho = lugar.getY();
		int principioX;
		int finX;
		int principioY;
		int finY;
		int max = this.tamanio - 1;
		int min = 0;
		int contadorY;
		Collection<Posicionable> Devolver = new ArrayList<Posicionable>();

		// seteo principio y final en X
		if (largo - rango < min) {
			principioX = min;
		} else {
			principioX = largo - rango;
		}
		if (largo + rango > max) {
			finX = max;
		} else {
			finX = largo + rango;
		}

		// seteo principio y final en Y
		if (ancho - rango < min) {
			principioY = min;
		} else {
			principioY = ancho - rango;
		}
		if (ancho + rango > max) {
			finY = max;
		} else {
			finY = ancho + rango;
		}

		while ((principioX <= finX)) {
			contadorY = principioY;
			while ((contadorY <= finY)) {
				Devolver.addAll(this.Listado[principioX][contadorY].getListado());
				contadorY++;
			}
			principioX++;
		}

		return Devolver;
	}

	private boolean enRango(int principioX, int principioY, int finX, int finY,
			Posicion posicionCasilla) {

		if (((principioX <= posicionCasilla.getX()) && (finX >= posicionCasilla.getX()))
				&& ((principioY <= posicionCasilla.getY()) && (finY >= posicionCasilla.getY()))) {
			return true;
		} else
			return false;

	}

	// Devuelve una lista donde el primer enemigo de la lista es el que debe ser
	// golpeado primero
	// El enemigo que debe ser golpeado primero es el que se encuentra mas
	// avanzado en el camino
	public Collection<Enemigo> enemigosEnRango(Casillero puntoCentral, int rango) {
		Posicion lugar = puntoCentral.getPosicion();
		int largo = lugar.getX();
		int ancho = lugar.getY();
		int principioX = 0, principioY = 0;
		int finX = 0, finY = 0;
		int max = this.tamanio - 1;
		int min = 0;
		Object objeto;
		Casillero casilla;
		Posicion posicionCasilla;
		Collection<Posicionable> objetos = new LinkedList<Posicionable>();
		Collection<Enemigo> enemigos = new LinkedList<Enemigo>();
		Collection<Casillero> caminoReal;

		// seteo principio y final en X
		if (largo - rango < min) {
			principioX = min;
		} else {
			principioX = largo - rango;
		}
		if (largo + rango > max) {
			finX = max;
		} else {
			finX = largo + rango;
		}

		// seteo principio y final en Y
		if (ancho - rango < min) {			
			principioY = min;
		} else {
			principioY = ancho - rango;
		}
		if (ancho + rango > max) {
			finY = max;
		} else {
			finY = ancho + rango;
		}

		caminoReal = this.camino;// (LinkedList) this.camino;
		Iterator<Casillero> itCaminoReal = caminoReal.iterator();

		// recorro el camino real en busca de casillero que esten en rango
		while (itCaminoReal.hasNext()) {
			casilla = itCaminoReal.next();
			posicionCasilla = casilla.getPosicion();

			if (enRango(principioX, principioY, finX, finY, posicionCasilla)) {

				objetos = casilla.getListado();
				Iterator<Posicionable> itObjetos = objetos.iterator();
				// Si esta en rango, de la lista de posicionables obtengo los
				// enemigos
				while (itObjetos.hasNext()) {
					objeto = itObjetos.next();
					// lleno la lista de enemigos
					if (objeto instanceof Enemigo) {
						enemigos.add((Enemigo) objeto);
					}
				}

			}

		}

		return enemigos;

	}// fin enmigosEnRango()

}